package ru.papergames.battleserver.model.battle.services;

import ru.common.util.MTRandom;
import ru.papergames.Config;
import ru.papergames.battleserver.model.battle.AbstractBattle;
import ru.papergames.battleserver.model.battle.BallColor;
import ru.papergames.battleserver.model.battle.GameBall;
import ru.papergames.battleserver.model.battle.map.BattleMap;
import ru.papergames.battleserver.model.battle.map.Cell;

import java.util.*;

/**
 * @author : atroshanin
 */
public class DefaultNewBallsThrowerImpl implements NewBallsThrower {

    private Random rand = MTRandom.getInstance().getSecureRandom();

    private static DefaultNewBallsThrowerImpl instance = new DefaultNewBallsThrowerImpl();

    public static DefaultNewBallsThrowerImpl getInstance() {
        return instance;
    }

    private DefaultNewBallsThrowerImpl() {
    }

    @Override
    public List<GameBall> throwNewBalls(AbstractBattle battle, BattleMap map) {
        SortedSet<Integer> nums = generateRandomNewBallsNums(map);
        List<Cell> randomFreeCells = new ArrayList<Cell>(nums.size());
        Iterator<Integer> iter = nums.iterator();
        int curInt = iter.next();
        int curSum = 0;
        int[] mass = map.getFreeCellsCountPerColumn();
        for (int i = 0; i < mass.length; i++) {

            int massI = mass[i];
            if (curInt < curSum + massI) {
                int cnt = 0;
                for (int k = 0; k < map.getHeight(); k++) {
                    Cell cell = map.getCell(i, k);
                    if (cell.getGameBall() == null) {
                        if (cnt + curSum == curInt) {
                            randomFreeCells.add(cell);
                            if (iter.hasNext()) {
                                curInt = iter.next();
                                if (curInt >= curSum + massI) {
                                    break;
                                }
                            } else {
                                i = mass.length + 1;
                                break;
                            }
                        }
                        cnt++;
                    }
                }
            }
            curSum = curSum + massI;
        }
        List<GameBall> result = new ArrayList<GameBall>(randomFreeCells.size());
        BallColor[] colors = battle.getColorsSetForRandomAccess();
        for (Cell cell : randomFreeCells) {
            GameBall ball = new GameBall(colors[rand.nextInt(colors.length)]);
            map.addNewGameBall(cell, ball);
            result.add(ball);
        }
        return result;
    }

    private SortedSet<Integer> generateRandomNewBallsNums(BattleMap map) {
        int freeCellsCount = map.getFreeCellsCount();
        TreeSet<Integer> nums = new TreeSet<Integer>();
        for (int i = 0; i < Config.NEW_BALLS_COUNT; i++) {

            int num = rand.nextInt(freeCellsCount);
            if (nums.size() == 0) {
                nums.add(num);
                continue;
            }
            while (nums.contains(num)) {
                num++;
                num = num >= freeCellsCount ? 0 : num;
            }
            nums.add(num);
        }
        return nums;
    }

}
